package io.feige.rpc.consumer;

import io.feige.rpc.consumer.config.RemoteServiceConfig;
import io.feige.rpc.consumer.config.RemoteServiceConfigManager;
import io.feige.rpc.consumer.config.ServiceSocketAddress;
import io.feige.rpc.consumer.handler.ClientInvokerHandler;
import io.feige.rpc.consumer.network.ConsumerConnectionService;
import io.feige.rpc.consumer.network.implement.ConsumerConnectionServiceImpl;
import io.feige.rpc.producer.RpcProducerService;
import io.feige.rpc.protocol.Protocol;
import io.feige.rpc.protocol.nettyobj.NettyObjectProtocol;

import java.io.InputStream;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

import org.jdom.Document;
import org.jdom.Element;
import org.jdom.input.SAXBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class RpcConsumerService { 
	
	private static Logger logger=LoggerFactory.getLogger(RpcConsumerService.class);
	
	private ConsumerConnectionService connectionService=new ConsumerConnectionServiceImpl();
	
	private RemoteServiceConfigManager remoteServiceConfigManager;
	
	private Protocol protocol;
	
	private String importConfig;
	
	public RpcConsumerService(){ 
		 
	}
	
	public void start(){
		String protocolName=null;
		try {
			InputStream inStream = RpcProducerService.class.getClassLoader().getResourceAsStream("feige.properties");
			Properties pro = new Properties();
			pro.load(inStream);
			protocolName=pro.getProperty("feige.protocol");
		} catch (Exception e) {
			logger.warn("classpath:feige.properties not found");
		}
		if (protocolName!=null) {
			try {
				protocol=(Protocol) Class.forName(protocolName.trim()).newInstance();
			} catch (Exception e) {
				new IllegalArgumentException(e);
			}
		}	
		
		if (importConfig==null) {
			importConfig="feige/feige-import.xml";
		}
		start(importConfig);
	}
	
	public void start(List<RemoteServiceConfig> configs){
		remoteServiceConfigManager=new RemoteServiceConfigManager(this);
		remoteServiceConfigManager.init(configs);
		connectionService.start(this);
	}
	
	@SuppressWarnings("unchecked")
	public void start(String configXml){
		List<RemoteServiceConfig> configs=new ArrayList<RemoteServiceConfig>();
		try {
			SAXBuilder sb = new SAXBuilder(); // 新建立构造器
			Document doc = null;
			doc = sb.build(RpcConsumerService.class.getClassLoader().getResourceAsStream(configXml));
			Element element = doc.getRootElement(); // 取得根节点 
			if(element != null) {
				List<Element> elementList = element.getChildren();
				for(Element ele:elementList){
					RemoteServiceConfig config=new RemoteServiceConfig();
					List<ServiceSocketAddress> hosts=new ArrayList<ServiceSocketAddress>();
					config.setHosts(hosts); 
					config.setService(ele.getChild("interface").getValue().trim()); 
					Element hostsEle = (Element) ele.getChildren("hosts").get(0);
					List<Element> hostsEles=hostsEle.getChildren();  
					for(Element hoste:hostsEles){
						ServiceSocketAddress ad=new ServiceSocketAddress(hoste.getChild("ip").getValue().trim(), Integer.parseInt(hoste.getChild("port").getValue().trim()), Integer.parseInt(hoste.getChild("weight").getValue().trim()));
						hosts.add(ad);
					}
					configs.add(config);
				}
			} 
		} catch (Exception e) {
			throw new IllegalArgumentException("check classpath:feige/feige-import.xml if exist");
		}
		start(configs);
	}
	
	@SuppressWarnings("unchecked")
	public <T> T getProxyService(Class<T> clazz){
		return (T)Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class[]{clazz}, new ClientInvokerHandler(this, clazz.getName()));
	}

	public RemoteServiceConfigManager getRemoteServiceConfigManager() {
		return remoteServiceConfigManager;
	}
	
	public ConsumerConnectionService getConnectionService() {
		return connectionService;
	}
 
	public Protocol getProtocol() {
		return protocol==null?new NettyObjectProtocol():protocol;
	}

	public void setProtocol(Protocol protocol) {
		this.protocol = protocol;
	}

	public String getImportConfig() {
		return importConfig;
	}

	public void setImportConfig(String importConfig) {
		this.importConfig = importConfig;
	}
	
	public void destroy(){
		getConnectionService().stop();
		getRemoteServiceConfigManager().destroy();
	}
}
